| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- <script>
- let { turn, role, streaming = false } = $props();
- const isUser = role === "user";
- const content = $derived(isUser ? turn.user_text : turn.llm_text);
- function formatDateTime(dateStr) {
- return new Date(dateStr).toLocaleString("en-US", {
- month: "short",
- day: "numeric",
- hour: "numeric",
- minute: "2-digit",
- hour12: true
- });
- }
- </script>
- <div class="message" class:user={isUser} class:assistant={!isUser}>
- <div class="bubble">
- <p class="text">
- {content}{#if streaming}<span class="cursor"></span>{/if}
- </p>
- {#if !streaming}
- <div class="meta">
- <span class="time">{formatDateTime(turn.created_at)}</span>
- {#if !isUser}
- <span class="dot">·</span>
- <span class="tokens">{turn.tokens_used} tokens</span>
- {/if}
- </div>
- {/if}
- </div>
- </div>
- <style>
- .message {
- display: flex;
- max-width: 100%;
- }
- .message.user {
- justify-content: flex-end;
- }
- .message.assistant {
- justify-content: flex-start;
- }
- .bubble {
- max-width: 72%;
- display: flex;
- flex-direction: column;
- gap: 0.4rem;
- }
- .message.user .bubble {
- align-items: flex-end;
- }
- .message.assistant .bubble {
- align-items: flex-start;
- }
- .text {
- padding: 0.75rem 1rem;
- border-radius: 16px;
- font-size: 0.95rem;
- line-height: 1.6;
- color: #e5e5ea;
- white-space: pre-wrap;
- word-break: break-word;
- }
- .message.user .text {
- background: #5a5aff;
- border-bottom-right-radius: 4px;
- }
- .message.assistant .text {
- background: #1a1a28;
- border: 1px solid #2a2a3a;
- border-bottom-left-radius: 4px;
- }
- .meta {
- display: flex;
- align-items: center;
- gap: 0.35rem;
- font-size: 0.72rem;
- color: #44445a;
- padding: 0 0.25rem;
- }
- .dot {
- color: #2a2a3a;
- }
- .cursor {
- display: inline-block;
- width: 2px;
- height: 1em;
- background: #a855f7;
- margin-left: 2px;
- vertical-align: text-bottom;
- border-radius: 1px;
- animation: blink 0.9s ease-in-out infinite;
- }
- @keyframes blink {
- 0%, 100% { opacity: 1; }
- 50% { opacity: 0; }
- }
- @media (max-width: 600px) {
- .bubble { max-width: 88%; }
- }
- </style>
|